﻿// ===============================================================================
// XCI.NET 西安交通信息WinForm开发框架 2018 版权所有
// ===============================================================================

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using XCI.Extensions;
using XCI.Helper;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System.Threading.Tasks;
using System.Threading;
using System.Net.Http.Handlers;

namespace XCI.Core
{
    /// <summary>
    /// WebApi通讯类
    /// </summary>
    public class WebApi
    {
        #region 私有字段

        //public WebApiBuilder Builder => new WebApiBuilder(this);
        private static readonly JsonSerializerSettings serializerSettings;
        private static readonly MediaTypeHeaderValue jsonMediaTypeHeader = new MediaTypeHeaderValue("application/json");
        protected readonly HttpClient client;
        private string _baseUrl;//基地址
        private bool _useProxy;
        #endregion

        #region 构造函数

        /// <summary>
        /// 静态构造函数
        /// </summary>
        static WebApi()
        {
            ServicePointManager.DefaultConnectionLimit = 5000;
            ServicePointManager.Expect100Continue = false;

            serializerSettings = new JsonSerializerSettings
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Error,
                NullValueHandling = NullValueHandling.Ignore,
                DateFormatString = "yyyy-MM-dd HH:mm:ss",
                ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver(),
                Formatting = Formatting.None
            };
            serializerSettings.Converters.Add(new StringEnumConverter { NamingStrategy = new CamelCaseNamingStrategy() });
        }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public WebApi() : this(null, TimeSpan.FromSeconds(15), false)
        {
        }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        /// <param name="timeout">超时时间</param>
        public WebApi(TimeSpan timeout) : this(string.Empty, timeout, false)
        {
        }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        /// <param name="baseUrl">服务器基地址</param>
        /// <param name="timeout">请求超时间隔</param>
        /// <param name="useProxy">是否使用代理</param>
        public WebApi(string baseUrl, TimeSpan timeout, bool useProxy)
        {
            this._baseUrl = baseUrl;
            this._useProxy = useProxy;
            client = new HttpClient(CreateClientHandler());
            InitHttpClient(client, timeout);
        }

        #endregion

        #region 公共函数

        private HttpClientHandler CreateClientHandler()
        {
            return new HttpClientHandler
            {
                UseCookies = false,
                AllowAutoRedirect = false,
                UseProxy = _useProxy,
                AutomaticDecompression = DecompressionMethods.GZip
            };
        }

        private void InitHttpClient(HttpClient _client, TimeSpan _timeout)
        {
            _client.DefaultRequestHeaders.ExpectContinue = false;
            _client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
            _client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
            _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            _client.DefaultRequestHeaders.Connection.Add("keep-alive");
            //_client.DefaultRequestHeaders.Add("X-Requested-With", "AppHttpRequest");
            _client.DefaultRequestHeaders.Add("HTTP_CLIENT_IP", NetHelper.GetLocalIP());
            _client.Timeout = _timeout;
        }

        /// <summary>
        /// 添加默认请求头
        /// </summary>
        /// <param name="headerData">请求头集合</param>
        public void AddDefaultHeader(IDictionary<string, string> headerData)
        {
            foreach (var item in headerData)
            {
                client.DefaultRequestHeaders.Add(item.Key, item.Value);
            }
        }

        /// <summary>
        /// 设置服务器基地址
        /// </summary>
        /// <param name="baseUrl">服务器基地址</param>
        public void SetBaseUrl(string baseUrl)
        {
            this._baseUrl = baseUrl;
        }

        /// <summary>
        /// 设置请求超时间隔
        /// </summary>
        /// <param name="timeout">请求超时间隔</param>
        public void SetTimeout(TimeSpan timeout)
        {
            client.Timeout = timeout;
        }

        /// <summary>
        /// 使用本类序列化规则序列化对象
        /// </summary>
        /// <param name="data">待序列化的对象</param>
        /// <returns>返回序列化后的字符串</returns>
        public string Serialize(object data)
        {
            return JsonHelper.Serialize(data, serializerSettings);
        }

        /// <summary>
        /// 使用本类序列化规则反序列化对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="json">json字符串</param>
        /// <returns>返回反序列化后的字符串</returns>
        public T Deserialize<T>(string json)
        {
            return JsonHelper.Deserialize<T>(json, serializerSettings);
        }

        /// <summary>
        /// 获取HttpClient对象
        /// </summary>
        public HttpClient GetClient()
        {
            return client;
        }

        #endregion

        #region 事件

        /// <summary>
        /// 在请求发送前触发
        /// </summary>
        /// <param name="request">请求对象</param>
        /// <returns>如果返回false,则终止请求</returns>
        protected virtual bool OnBeforeRequest(HttpRequestMessage request)
        {
            return true;
        }

        /// <summary>
        /// 在请求成功后触发
        /// </summary>
        /// <param name="response">响应对象</param>
        protected virtual void OnAfterRequest(HttpResponseMessage response)
        {
        }

        #endregion

        #region Get

        /// <summary>
        /// Get请求返回字符串
        /// </summary>
        /// <param name="url">接口路径</param>
        /// <param name="data">请求数据</param>
        /// <returns>返回字符串</returns>
        public string Get(string url, object data = null)
        {
            var sdata = GetParamDic(data);
            url = WebHelper.BuildGetUrl(_baseUrl, url, sdata);
            var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
            if (!OnBeforeRequest(requestMessage)) return string.Empty;
            var responseMessage = client.SendAsync(requestMessage).Result;
            responseMessage.EnsureSuccessStatusCode();
            OnAfterRequest(responseMessage);
            return responseMessage.Content.ReadAsStringAsync().Result;
        }

        /// <summary>
        /// Get请求返回泛型消息对象
        /// </summary>
        /// <typeparam name="T">接收数据类型</typeparam>
        /// <param name="url">接口路径</param>
        /// <param name="data">请求数据</param>
        /// <returns>返回泛型消息对象</returns>
        public BoolMessage<T> Get<T>(string url, object data = null) where T : class
        {
            var resultString = Get(url, data);
            return GetResultData(resultString, default(T));
        }

        /// <summary>
        /// Get请求返回通用消息对象
        /// </summary>
        /// <param name="url">接口路径</param>
        /// <param name="data">请求数据</param>
        /// <returns>返回通用消息对象</returns>
        public BoolMessage GetAsMessage(string url, object data = null)
        {
            var resultString = Get(url, data);
            return GetResultMessage(resultString);
        }

        #endregion

        #region Post

        /// <summary>
        /// Post请求返回字符串
        /// </summary>
        /// <param name="url">接口路径</param>
        /// <param name="data">请求数据</param>
        /// <returns>返回字符串</returns>
        public string Post(string url, object data = null)
        {
            if (data == null) return PostCore(url, null);
            var sdata = GetParamDic(data);
            HttpContent content = new FormUrlEncodedContent(ToNameValueCollection(sdata));
            return PostCore(url, content);
        }

        /// <summary>
        /// Post请求返回泛型消息对象
        /// </summary>
        /// <typeparam name="T">接收数据类型</typeparam>
        /// <param name="url">接口路径</param>
        /// <param name="data">请求数据</param>
        /// <returns>返回泛型消息对象</returns>
        public BoolMessage<T> Post<T>(string url, object data = null)
        {
            var resultString = Post(url, data);
            return GetResultData(resultString, default(T));
        }

        /// <summary>
        /// Post请求返回通用消息对象
        /// </summary>
        /// <param name="url">接口路径</param>
        /// <param name="data">请求数据</param>
        /// <returns>返回通用消息对象</returns>
        public BoolMessage PostAsMessage(string url, object data = null)
        {
            var resultString = Post(url, data);
            return GetResultMessage(resultString);
        }

        /// <summary>
        /// 以Json方式Post请求返回字符串
        /// </summary>
        /// <param name="url">接口路径</param>
        /// <param name="data">请求数据</param>
        /// <returns>返回字符串</returns>
        public string PostJson(string url, object data = null)
        {
            if (data == null) return PostCore(url, null);
            var content = new StringContent(JsonHelper.Serialize(data, serializerSettings), Encoding.UTF8);
            content.Headers.ContentType = jsonMediaTypeHeader;
            return PostCore(url, content);
        }

        /// <summary>
        /// 以Json方式Post请求返回泛型消息对象
        /// </summary>
        /// <typeparam name="T">接收数据类型</typeparam>
        /// <param name="url">接口路径</param>
        /// <param name="data">请求数据</param>
        /// <returns>返回泛型消息对象</returns>
        public BoolMessage<T> PostJson<T>(string url, object data = null) where T : class
        {
            var resultString = PostJson(url, data);
            return GetResultData(resultString, default(T));
        }

        /// <summary>
        /// 以Json方式Post请求返回通用消息对象
        /// </summary>
        /// <param name="url">接口路径</param>
        /// <param name="data">请求数据</param>
        /// <returns>返回通用消息对象</returns>
        public BoolMessage PostJsonAsMessage(string url, object data = null)
        {
            var resultString = PostJson(url, data);
            return GetResultMessage(resultString);
        }

        /// <summary>
        /// Post请求核心方法
        /// </summary>
        /// <param name="url">接口路径</param>
        /// <param name="httpContent">请求数据对象</param>
        /// <returns>返回服务响应字符串</returns>
        private string PostCore(string url, HttpContent httpContent)
        {
            url = WebHelper.BuildGetUrl(_baseUrl, url);
            var requestMessage = new HttpRequestMessage(HttpMethod.Post, url);
            if (!OnBeforeRequest(requestMessage)) return string.Empty;
            //BuildRequestHeaders(requestMessage, headers);
            string Send()
            {
                var responseMessage = client.SendAsync(requestMessage).Result;
                responseMessage.EnsureSuccessStatusCode();
                OnAfterRequest(responseMessage);
                return responseMessage.Content.ReadAsStringAsync().Result;
            }

            if (httpContent == null) return Send();
            using (httpContent)
            {
                requestMessage.Content = httpContent;
                return Send();
            }
        }

        #endregion

        #region Upload

        /// <summary>
        /// 上传文件返回响应字符串
        /// </summary>
        /// <param name="url">接口路径</param>
        /// <param name="displayName">文件显示名称</param>
        /// <param name="filePath">待上传的本地文件路径</param>
        /// <param name="data">请求数据</param>
        /// <param name="cancellationTokenSource">取消标记</param>
        /// <param name="progress">进度报告</param>
        /// <returns>返回服务器响应字符串</returns>
        public string UploadFile(string url, string displayName, string filePath, object data = null,
           Action<HttpProgressArgs> progress = null, CancellationTokenSource cancellationTokenSource = null)
        {
            const int bufferSize = 81920;
            if (cancellationTokenSource == null)
            {
                cancellationTokenSource = new CancellationTokenSource();
            }
            url = WebHelper.BuildGetUrl(_baseUrl, url);
            var requestMessage = new HttpRequestMessage(HttpMethod.Post, url);
            if (!OnBeforeRequest(requestMessage)) return string.Empty;
            var sdata = GetParamDic(data);
            using (var content = new MultipartFormDataContent())
            {
                if (File.Exists(filePath))
                {
                    content.Add(new StreamContent(File.OpenRead(filePath), bufferSize), "uFile", displayName);
                }

                if (sdata != null && sdata.Count > 0)
                {
                    foreach (KeyValuePair<string, object> item in sdata)
                    {
                        content.Add(new StringContent(item.Value.ToStringOrEmpty()), item.Key);
                    }
                }
                requestMessage.Content = content;
                if (progress == null)
                {
                    var responseMessage = client.SendAsync(requestMessage, cancellationTokenSource.Token).Result;
                    responseMessage.EnsureSuccessStatusCode();
                    OnAfterRequest(responseMessage);
                    return responseMessage.Content.ReadAsStringAsync().Result;
                }
                else
                {
                    HttpProgressArgs httpProgressArgs = new HttpProgressArgs();
                    ProgressMessageHandler processMessageHander = new ProgressMessageHandler(CreateClientHandler());
                    processMessageHander.HttpSendProgress += (s, e) =>
                    {
                        httpProgressArgs.BytesTransferred = e.BytesTransferred;
                        httpProgressArgs.TotalBytes = e.TotalBytes.HasValue ? e.TotalBytes.Value : 0;
                        httpProgressArgs.ProgressPercentage = e.ProgressPercentage;
                        progress.Invoke(httpProgressArgs);
                    };
                    using (HttpClient localClient = new HttpClient(processMessageHander))
                    {
                        var responseMessage = localClient.SendAsync(requestMessage, cancellationTokenSource.Token).Result;
                        responseMessage.EnsureSuccessStatusCode();
                        OnAfterRequest(responseMessage);
                        return responseMessage.Content.ReadAsStringAsync().Result;
                    }
                }
            }
        }

        /// <summary>
        /// 上传文件返回泛型消息对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="url">接口路径</param>
        /// <param name="displayName">文件显示名称</param>
        /// <param name="filePath">待上传的本地文件路径</param>
        /// <param name="data">请求数据</param>
        /// <param name="cancellationTokenSource">取消标记</param>
        /// <param name="progress">进度报告</param>
        /// <returns>返回泛型消息对象</returns>
        public BoolMessage<T> UploadFile<T>(string url, string displayName, string filePath, object data = null,
            Action<HttpProgressArgs> progress = null, CancellationTokenSource cancellationTokenSource = null) where T : class
        {
            var resultString = UploadFile(url, displayName, filePath, data, progress, cancellationTokenSource);
            return GetResultData(resultString, default(T));
        }

        /// <summary>
        /// 上传字节数组
        /// </summary>
        /// <param name="url">接口地址</param>
        /// <param name="displayName">文件显示名称</param>
        /// <param name="fileData">字节数组</param>
        /// <param name="data">请求数据</param>
        /// <return>返回服务器响应字符串</return>
        public string UploadByte(string url, string displayName, byte[] fileData, object data = null)
        {
            url = WebHelper.BuildGetUrl(_baseUrl, url);
            var requestMessage = new HttpRequestMessage(HttpMethod.Post, url);
            if (!OnBeforeRequest(requestMessage)) return string.Empty;
            //BuildRequestHeaders(requestMessage, headers);
            var sdata = GetParamDic(data);
            using (var content = new MultipartFormDataContent())
            {
                content.Add(new ByteArrayContent(fileData), "uFile", displayName);

                if (sdata != null && sdata.Count > 0)
                {
                    foreach (KeyValuePair<string, object> item in sdata)
                    {
                        content.Add(new StringContent(item.Value.ToStringOrEmpty()), item.Key);
                    }
                }

                requestMessage.Content = content;
                var responseMessage = client.SendAsync(requestMessage).Result;
                responseMessage.EnsureSuccessStatusCode();
                OnAfterRequest(responseMessage);
                return responseMessage.Content.ReadAsStringAsync().Result;
            }
        }

        /// <summary>
        /// 上传字节数组
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="url">接口地址</param>
        /// <param name="displayName">文件显示名称</param>
        /// <param name="fileData">字节数组</param>
        /// <param name="data">请求数据</param>
        /// <returns>返回泛型消息对象</returns>
        public BoolMessage<T> UploadByte<T>(string url, string displayName, byte[] fileData, object data = null) where T : class
        {
            var resultString = UploadByte(url, displayName, fileData, data);
            return GetResultData(resultString, default(T));
        }

        #endregion

        #region Download

        /// <summary>
        /// 用Get方法下载文件到本地
        /// </summary>
        /// <param name="url">接口路径</param>
        /// <param name="data">请求数据</param>
        /// <param name="savePath">文件本地保存路径</param>
        /// <param name="cancellationTokenSource">取消标记</param>
        /// <param name="progress">进度报告</param>
        /// <returns>返回通用消息对象</returns>
        public BoolMessage Download(string url, object data, string savePath,
           Action<HttpProgressArgs> progress = null, CancellationTokenSource cancellationTokenSource = null)
        {
            var sdata = GetParamDic(data);
            url = WebHelper.BuildGetUrl(_baseUrl, url, sdata);
            HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
            if (!OnBeforeRequest(requestMessage)) return BoolMessage.False;
            //BuildRequestHeaders(requestMessage, headers);

            return DownloadFileCore(requestMessage, savePath, progress, cancellationTokenSource);
        }

        /// <summary>
        /// 用Get方法下载文件到字节数组
        /// </summary>
        /// <param name="url">接口路径</param>
        /// <param name="data">请求数据</param>
        /// <returns>返回泛型消息对象</returns>
        public BoolMessage<byte[]> Download(string url, object data = null)
        {
            var sdata = GetParamDic(data);
            url = WebHelper.BuildGetUrl(_baseUrl, url, sdata);
            HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
            if (!OnBeforeRequest(requestMessage)) return BoolMessage<byte[]>.False;
            //BuildRequestHeaders(requestMessage, headers);

            var responseMessage = client.SendAsync(requestMessage).Result;
            responseMessage.EnsureSuccessStatusCode();
            OnAfterRequest(responseMessage);

            return DownloadCore(responseMessage);
        }

        /// <summary>
        /// 用Post方法下载文件到本地
        /// </summary>
        /// <param name="url">接口路径</param>
        /// <param name="data">请求数据</param>
        /// <param name="savePath">文件本地保存路径</param>
        /// <param name="cancellationTokenSource">取消标记</param>
        /// <param name="progress">进度报告</param>
        /// <returns>返回通用消息对象</returns>
        public BoolMessage DownloadPost(string url, object data, string savePath,
            Action<HttpProgressArgs> progress = null, CancellationTokenSource cancellationTokenSource = null)
        {
            url = WebHelper.BuildGetUrl(_baseUrl, url);
            var sdata = GetParamDic(data);
            var requestMessage = new HttpRequestMessage(HttpMethod.Post, url);
            if (!OnBeforeRequest(requestMessage)) return null;
            //BuildRequestHeaders(requestMessage);
            using (var content = new FormUrlEncodedContent(ToNameValueCollection(sdata)))
            {
                requestMessage.Content = content;
                return DownloadFileCore(requestMessage, savePath, progress, cancellationTokenSource);
            }
        }

        /// <summary>
        /// 用Post方法下载文件到字节数组
        /// </summary>
        /// <param name="url">接口路径</param>
        /// <param name="data">请求数据</param>
        /// <returns>返回泛型消息对象</returns>
        public BoolMessage<byte[]> DownloadPost(string url, object data = null)
        {
            url = WebHelper.BuildGetUrl(_baseUrl, url);
            var sdata = GetParamDic(data);
            var requestMessage = new HttpRequestMessage(HttpMethod.Post, url);
            if (!OnBeforeRequest(requestMessage)) return null;
            //BuildRequestHeaders(requestMessage);
            using (var content = new FormUrlEncodedContent(ToNameValueCollection(sdata)))
            {
                requestMessage.Content = content;
                var responseMessage = client.SendAsync(requestMessage).Result;
                responseMessage.EnsureSuccessStatusCode();
                OnAfterRequest(responseMessage);

                return DownloadCore(responseMessage);
            }
        }

        //public BoolMessage DownloadPostJson(string url, object data, string savePath)
        //{
        //    var result = DownloadPostJson(url, data);
        //    if (result.Success && result.Data != null && result.Data.Length > 0)
        //    {
        //        IOHelper.CreateDirectoryByPath(savePath);
        //        return IOHelper.WriteFile(result.Data, savePath);
        //    }
        //    return new BoolMessage(result.Success, result.Msg);
        //}

        //public BoolMessage<byte[]> DownloadPostJson(string url, object data)
        //{
        //    url = WebHelper.BuildGetUrl(_baseUrl, url);
        //    var requestMessage = new HttpRequestMessage(HttpMethod.Post, url);
        //    if (!OnBeforeRequest(requestMessage)) return null;
        //    //BuildRequestHeaders(requestMessage);
        //    using (var content = new StringContent(JsonHelper.Serialize(data, serializerSettings), Encoding.UTF8))
        //    {
        //        content.Headers.ContentType = jsonMediaTypeHeader;
        //        requestMessage.Content = content;
        //        var responseMessage = client.SendAsync(requestMessage).Result;
        //        responseMessage.EnsureSuccessStatusCode();
        //        OnAfterRequest(responseMessage);
        //        return DownloadCore(responseMessage);
        //    }
        //}

        /// <summary>
        /// 文件下载结果统一处理函数
        /// </summary>
        /// <param name="responseMessage">服务响应对象</param>
        private BoolMessage<byte[]> DownloadCore(HttpResponseMessage responseMessage)
        {
            var mediaType = responseMessage.Content.Headers.ContentType.MediaType;
            if (mediaType.Equals("application/octet-stream", StringComparison.OrdinalIgnoreCase)
            || mediaType.IndexOf("image", StringComparison.OrdinalIgnoreCase) > -1)
            {
                Stream stream = responseMessage.Content.ReadAsStreamAsync().Result;
                byte[] bytes = new byte[stream.Length];
                stream.Read(bytes, 0, bytes.Length);
                stream.Seek(0, SeekOrigin.Begin);
                return new BoolMessage<byte[]>(true, bytes);
            }
            if (mediaType.Equals("application/md5-identical", StringComparison.OrdinalIgnoreCase))
            {
                return new BoolMessage<byte[]>(true, "md5一致,默认不传输", null);
            }

            var result = Deserialize<BoolMessage>(responseMessage.Content.ReadAsStringAsync().Result);
            return new BoolMessage<byte[]>(result.Success, result.Msg);
        }

        /// <summary>
        /// 文件下载结果统一处理函数
        /// </summary>
        private BoolMessage DownloadFileCore(HttpRequestMessage requestMessage, string savePath,
            Action<HttpProgressArgs> progress = null, CancellationTokenSource cancellationTokenSource = null)
        {
            const int bufferSize = 81920;
            if (cancellationTokenSource == null)
            {
                cancellationTokenSource = new CancellationTokenSource();
            }
            var cancellationToken = cancellationTokenSource.Token;
            using (var responseMessage = client.SendAsync(requestMessage,
                HttpCompletionOption.ResponseHeadersRead, cancellationToken).Result)
            {
                responseMessage.EnsureSuccessStatusCode();
                OnAfterRequest(responseMessage);

                var mediaType = responseMessage.Content.Headers.ContentType.MediaType;
                if (mediaType.Equals("application/octet-stream", StringComparison.OrdinalIgnoreCase)
                || mediaType.IndexOf("image", StringComparison.OrdinalIgnoreCase) > -1)
                {
                    IOHelper.CreateDirectoryByPath(savePath);
                    using (var fileStream = File.Open(savePath, FileMode.Create))
                    {
                        var contentLength = responseMessage.Content.Headers.ContentLength;
                        using (Stream stream = responseMessage.Content.ReadAsStreamAsync().Result)
                        {
                            byte[] buffer = new byte[bufferSize];
                            int count;
                            HttpProgressArgs httpProgressArgs = new HttpProgressArgs();

                            if (progress != null)
                            {
                                if (contentLength.HasValue) httpProgressArgs.TotalBytes = contentLength.Value;
                                progress.Invoke(httpProgressArgs);
                            }

                            while ((count = stream.ReadAsync(buffer, 0, buffer.Length).Result) != 0)
                            {
                                fileStream.Write(buffer, 0, count);
                                if (progress != null)
                                {
                                    httpProgressArgs.BytesTransferred += count;
                                    var current = Convert.ToInt32(httpProgressArgs.BytesTransferred / 1024m);
                                    var total = Convert.ToInt32(httpProgressArgs.TotalBytes / 1024m);
                                    httpProgressArgs.ProgressPercentage = 0;
                                    if (total > 0)
                                    {
                                        httpProgressArgs.ProgressPercentage = Convert.ToInt32(current * 100m / total);
                                    }
                                    progress.Invoke(httpProgressArgs);
                                }
                            }
                        }
                    }
                    return BoolMessage.True;
                }
                else if (mediaType.Equals("application/md5-identical", StringComparison.OrdinalIgnoreCase))
                {
                    return new BoolMessage(true, "md5一致,默认不传输", null);
                }
                var result = responseMessage.Content.ReadAsStringAsync().Result;
                return Deserialize<BoolMessage>(result);
            }
        }
        #endregion

        #region 内部私有函数

        /// <summary>
        /// 获取参数对象字典
        /// </summary>
        /// <param name="data">数据对象,支持字典类和普通对象</param>
        /// <returns>返回参数字典</returns>
        private IDictionary<string, object> GetParamDic(object data)
        {
            IDictionary<string, object> sdata = null;
            if (data != null)
            {
                sdata = data is IDictionary<string, object> dictionary
                    ? dictionary
                    : ObjectHelper.GetPropertyKeyValuePair(data);
            }
            return sdata ?? new Dictionary<string, object>();
        }

        /// <summary>
        /// 根据字典集合转为键值对集合
        /// </summary>
        /// <param name="datas">字典集合</param>
        private IEnumerable<KeyValuePair<string, string>> ToNameValueCollection(IDictionary<string, object> datas)
        {
            var dic = new Dictionary<string, string>();
            foreach (KeyValuePair<string, object> item in datas)
            {
                dic[item.Key] = item.Value.ToStringOrEmpty();
            }
            return dic;
        }

        /// <summary>
        /// 把响应字符串转为通用消息对象
        /// </summary>
        /// <param name="resultString">服务响应字符串</param>
        /// <returns>返回通用消息对象</returns>
        private BoolMessage GetResultMessage(string resultString)
        {
            var boolMessage = Deserialize<BoolMessage>(resultString);
            return boolMessage;
        }

        /// <summary>
        /// 把响应字符串转为泛型消息对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="resultString">服务响应字符串</param>
        /// <param name="defaultValue">如果没有找到对应的数据时的默认值</param>
        /// <returns>返回泛型消息对象</returns>
        private BoolMessage<T> GetResultData<T>(string resultString, T defaultValue)
        {
            Type targetType = typeof(T);
            if (targetType.IsPrimitive || targetType == TypeHelper.StringType
                || targetType == TypeHelper.DateTimeType)
            {
                return Deserialize<BoolMessage<T>>(resultString);
            }
            var boolMessage = Deserialize<BoolMessage>(resultString);
            var data = boolMessage.Data != null ? JsonHelper.ToObject<T>(boolMessage.Data) : defaultValue;
            return new BoolMessage<T>(boolMessage.Success, boolMessage.Msg, data);
        }

        #endregion
    }

    public struct HttpProgressArgs
    {
        public long BytesTransferred { get; internal set; }
        public long TotalBytes { get; internal set; }
        public int ProgressPercentage { get; internal set; }
    }
}